import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import warnings

warnings.filterwarnings('ignore')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False


class Problem2Optimizer:
    """问题2：灌溉系统布线与储水罐优化模型"""

    def __init__(self):
        # 文档给定参数
        self.farm_area = 10000  # 农场面积1公顷=10000平方米（100m×100m）
        self.min_soil_moisture = 0.22  # 作物存活最低土壤湿度{insert\_element\_0\_}
        self.pipe_cost_coeff = (50, 1.2, 0.1, 1.5)  # 管道成本参数C=50L^1.2 + 0.1Q^1.5{insert\_element\_1\_}
        self.tank_cost_per_liter = 5  # 储水罐单位容积成本{insert\_element\_2\_}
        self.sprinkler_radius = 15  # 喷头覆盖半径15米{insert\_element\_3\_}
        self.data_period = ('2021-07-01', '2021-07-31')  # 问题2指定数据时间段{insert\_element\_4\_}

    def generate_july_mock_data(self):
        """生成符合文档逻辑的2021年7月土壤湿度与气象数据"""
        print("=== 生成7月模拟数据（问题2） ===")
        # 生成7月1日-7月31日的日级数据
        dates = pd.date_range(self.data_period[0], self.data_period[1], freq='D')
        n_days = len(dates)

        # 模拟每日土壤湿度（部分天数低于最低值，需要灌溉）
        np.random.seed(42)
        soil_moisture = np.clip(
            0.25 + np.random.normal(0, 0.05, n_days),
            0.18, 0.4  # 确保存在低于0.22的情况
        )

        # 生成土壤湿度数据框
        soil_data = pd.DataFrame({
            'Date': dates,
            '5cm_SM': soil_moisture
        })

        # 模拟每日需水量（基于文档绝对湿度公式推导）
        # 需水量 = (最低湿度 - 实际湿度) × 单位面积土壤干重 × 农场面积 / 100
        # 单位面积土壤干重=1500kg/m³{insert\_element\_5\_}
        soil_data['需水量(L)'] = np.where(
            soil_data['5cm_SM'] < self.min_soil_moisture,
            (self.min_soil_moisture - soil_data['5cm_SM']) * 1500 * self.farm_area / 100,
            0
        )

        print(f"✅ 生成7月{self.data_period[0]}至{self.data_period[1]}共{n_days}天数据")
        print(f"其中需灌溉天数：{sum(soil_data['需水量(L)'] > 0)}天，总需水量：{soil_data['需水量(L)'].sum():.2f}L")
        return soil_data

    def calculate_sprinkler_layout(self):
        """计算喷头布置方案（满足相邻间距≥15米，覆盖全农场）"""
        # 100m×100m农场，按15米半径均匀布置喷头
        grid_size = self.sprinkler_radius  # 网格间隔=喷头半径（确保覆盖无死角）
        x_coords = np.arange(grid_size, 100, grid_size)  # x轴喷头坐标
        y_coords = np.arange(grid_size, 100, grid_size)  # y轴喷头坐标
        n_sprinklers = len(x_coords) * len(y_coords)

        # 喷头成本（假设每个喷头基础成本200元）
        sprinkler_cost = n_sprinklers * 200
        print(f"\n喷头布置：{n_sprinklers}个（网格{grid_size}m×{grid_size}m），总成本：{sprinkler_cost:.2f}元")
        return n_sprinklers, sprinkler_cost

    def optimize_pipe_and_tank(self, soil_data):
        """优化引水管和储水罐配置，最小化总建设成本"""
        print("\n=== 优化引水管与储水罐（问题2核心） ===")
        # 提取需水量特征
        daily_need = soil_data[soil_data['需水量(L)'] > 0]['需水量(L)']
        avg_daily_need = daily_need.mean()  # 日均需水量（用于计算管道流量）
        max_daily_need = daily_need.max()  # 最大日需水量（用于设计储水罐容积）

        # 1. 计算引水管成本
        # 假设农场距河流距离L=80米（可根据实际调整）
        L = 80
        Q = avg_daily_need  # 管道日流量=日均需水量
        pipe_cost = self.pipe_cost_coeff[0] * (L ** self.pipe_cost_coeff[1]) + \
                    self.pipe_cost_coeff[2] * (Q ** self.pipe_cost_coeff[3])
        print(f"引水管：长度{L}米，日流量{Q:.2f}L，成本：{pipe_cost:.2f}元")

        # 2. 计算储水罐成本
        # 储水罐容积=3倍最大日需水量（应对连续干旱）
        tank_volume = max_daily_need * 3
        tank_cost = tank_volume * self.tank_cost_per_liter
        print(f"储水罐：容积{tank_volume:.2f}L，成本：{tank_cost:.2f}元")

        return pipe_cost, tank_cost, L, tank_volume

    def run_optimization(self):
        """执行问题2完整优化流程"""
        # 步骤1：生成7月数据
        soil_data = self.generate_july_mock_data()

        # 步骤2：计算喷头成本
        n_sprinklers, sprinkler_cost = self.calculate_sprinkler_layout()

        # 步骤3：优化管道和储水罐
        pipe_cost, tank_cost, pipe_length, tank_volume = self.optimize_pipe_and_tank(soil_data)

        # 步骤4：计算总费用
        total_cost = pipe_cost + tank_cost + sprinkler_cost
        print(f"\n=== 问题2优化结果 ===")
        print(f"总建设成本：{total_cost:.2f}元（管道+储水罐+喷头）")
        print(f"配置详情：管道{pipe_length}米，储水罐{tank_volume:.2f}L，喷头{n_sprinklers}个")

        # 可视化7月需水量
        plt.figure(figsize=(12, 6))
        plt.bar(soil_data['Date'], soil_data['需水量(L)'], color='skyblue')
        plt.axhline(y=0, color='r', linestyle='--', label=f'最低湿度阈值（{self.min_soil_moisture}）')
        plt.title('2021年7月每日灌溉需水量')
        plt.xlabel('日期')
        plt.ylabel('需水量（L）')
        plt.xticks(rotation=45)
        plt.tight_layout()
        plt.show()

        return {
            '总费用': total_cost,
            '管道成本': pipe_cost,
            '储水罐成本': tank_cost,
            '喷头成本': sprinkler_cost,
            '管道长度': pipe_length,
            '储水罐容积': tank_volume,
            '喷头数量': n_sprinklers
        }


if __name__ == "__main__":
    optimizer = Problem2Optimizer()
    result = optimizer.run_optimization()